<?php
class galaxy {
	static $instance = NULL;
	function __construct() {
		if(self::$instance===NULL) {//单例判断
			self::$instance = $this;
		} else {
			self::halt("Duplicate galaxy instance");
		}
		$this->init_const();
		$this->init_env();
		$this->init_user();
		$_ENV['g'] = $this;
	}
	static function halt($msg) {
		halt($msg);
	}
	
	static function getInstance() {//获取实例
		if(self::$instance===NULL) {
			self::$instance = new self;
		}
		return self::$instance;
	}
	
	//initial
	function init_const() {
	    if( !defined('EXTR_PREFIX_ALL') ) define('EXTR_PREFIX_ALL', 3);
	    if( !defined('EXTR_PREFIX_INVALID') ) define('EXTR_PREFIX_INVALID', 4);
	    if( !defined('EXTR_IF_EXISTS') ) define('EXTR_IF_EXISTS', 5);
	    if( !defined('EXTR_PREFIX_IF_EXISTS') ) define('EXTR_PREFIX_IF_EXISTS', 6);
	    if( !defined('EXTR_REFS') ) define('EXTR_REFS', 256);
	    define('ATTACH_PATH', APP_PATH.C('ATTACH_PATH'));
	}
	function init_env() {
		//time
		$timestamp = time();
		$timeoffset = 8;
			
		//ip
		if($_SERVER['HTTP_CLIENT_IP'] && strcasecmp($_SERVER['HTTP_CLIENT_IP'], 'unknown')) {
			$onlineip = $_SERVER['HTTP_CLIENT_IP'];
		} elseif($_SERVER['HTTP_X_FORWARDED_FOR'] && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown')) {
			$onlineip = $_SERVER['HTTP_X_FORWARDED_FOR'];
		} elseif($_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
			$onlineip = $_SERVER['REMOTE_ADDR'];
		} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
			$onlineip = $_SERVER['REMOTE_ADDR'];
		}
		preg_match("/[\d\.]{7,15}/", $onlineip, $onlineipmatches);
		$onlineip = $onlineipmatches[0] ? $onlineipmatches[0] : 'unknown';
		unset($onlineipmatches);
		unset($_ENV);
		$_ENV = array();
		$title = 'Galaxy '.C('GALX_VER');
		self::extract_to(get_defined_vars(), $_ENV, EXTR_SKIP);
		
		$ch = strtoupper(C('PATH_INFO_CHARSET'));
		if($ch!='UTF-8') {
			foreach($_GET as $k=>$v) {
				$_GET[$k] = iconv($ch, 'UTF-8', $v);
				$_REQUEST[$k] = iconv($ch, 'UTF-8', $v);
			}
			foreach(array('URL', 'REQUEST_URI', 'PATH_INFO', 'PATH_TRANSLATED', 'ORIG_PATH_INFO', 'ORIG_PATH_TRANSLATED') as $v)
				$_SERVER[$v] = iconv($ch, 'UTF-8', $_SERVER[$v]);
		}

		//Slash the input
		foreach(array('_GET','_POST','_REQUEST') as $v) $$v = self::gaddslashes($$v, 0, true);
	}
	function init_user() {
		list($uid, $username) = gUser::auth();
		self::extract_to(get_defined_vars(), $this);
	}
	
	//global functions
  static function extract_to( &$arr, &$to, $type=EXTR_OVERWRITE, $prefix=false ){
        if( $type & EXTR_REFS ) {
        	$type ^= EXTR_REFS;
        	$ref = true;
        } else {
        	$ref = false;
        }
      
      if( !is_array( $arr ) ) return trigger_error("extract_to(): First argument should be an array", E_USER_WARNING );
      
      if( is_array( $to ) ) $t=0;
      else if( is_object( $to ) ) $t=1;
      else return trigger_error("extract_to(): Second argument should be an array or object", E_USER_WARNING );
      
      if( $type==EXTR_PREFIX_SAME || $type==EXTR_PREFIX_ALL || $type==EXTR_PREFIX_INVALID || $type==EXTR_PREFIX_IF_EXISTS )
          if( $prefix===false ) return trigger_error("extract_to(): Prefix expected to be specified", E_USER_WARNING ); 
          else $prefix .= '_';
      
      $i=0;
      foreach( $arr as $key=>$val ){
          $nkey = $key;
          $isset = $t==0 ? isset( $to[$key] ) : isset( $to->$key );
          
          if( ( $type==EXTR_SKIP && $isset ) 
              || ( $type==EXTR_IF_EXISTS && !$isset ) )
                  continue;
          
          else if( ( $type==EXTR_PREFIX_SAME && $isset )
              || ( $type==EXTR_PREFIX_ALL )
              || ( $type==EXTR_PREFIX_INVALID && !preg_match( '#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#', $key ) ) )
                  $nkey = $prefix.$key;
                  
          else if( $type==EXTR_PREFIX_IF_EXISTS )
              if( $isset ) $nkey = $prefix.$key;
              else continue;

          if( !preg_match( '#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#', $nkey ) ) continue;
          
          if( $t==1 )
              if( $ref ) $to->$nkey = &$arr[$key];
              else $to->$nkey = $val;
          else 
              if( $ref ) $to[$nkey] = &$arr[$key];
              else $to[$nkey] = $val;
          
          $i++;
      }
      
      return $i;
  }
  
	static function authcode($string, $operation = 'DECODE', $expiry = 0, $key = '') {
	
		$ckey_length = 4;
	
		$key = md5($key ? $key : UC_KEY);
		$keya = md5(substr($key, 0, 16));
		$keyb = md5(substr($key, 16, 16));
		$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
	
		$cryptkey = $keya.md5($keya.$keyc);
		$key_length = strlen($cryptkey);
	
		$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
		$string_length = strlen($string);
	
		$result = '';
		$box = range(0, 255);
	
		$rndkey = array();
		for($i = 0; $i <= 255; $i++) {
			$rndkey[$i] = ord($cryptkey[$i % $key_length]);
		}
	
		for($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}
	
		for($a = $j = $i = 0; $i < $string_length; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}
	
		if($operation == 'DECODE') {
			if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
				return substr($result, 26);
			} else {
				return '';
			}
		} else {
			return $keyc.str_replace('=', '', base64_encode($result));
		}
	
	}

	static function gaddslashes($string, $force = 0, $strip = FALSE) {
		defined('MAGIC_QUOTES_GPC') or define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
		if(!MAGIC_QUOTES_GPC || $force) {
			if(is_array($string)) {
				foreach($string as $key => $val) {
					$string[$key] = self::gaddslashes($val, $force, $strip);
				}
			} else {
				$string = addslashes($strip ? stripslashes($string) : $string);
			}
		}
		return $string;
	}
	
	static function gcookie($name, $value='', $life=86400000) {
		$name = C('COOKIE_PREFIX').$name;
		if(func_num_args()==1) return $_COOKIE[$name];
		setcookie($name, $value,
			$_ENV['timestamp'] + $life, C('COOKIE_PATH'),
			C('COOKIE_DOMAIN'), $_SERVER['SERVER_PORT'] == 443 ? 1 : 0);
	}
	
	//弱token(无Session)
	static function checkToken(&$data) {
		$name   = C('TOKEN_NAME');
		$type   = C('TOKEN_TYPE');
		if(empty($data[$name]) || $type(microtime(true)) != $data[$name])
			return false;
		unset($data[$name]);
		return true;
	}
	
	static function footerExtra($code = '') {
		static $return = false;
		if($return===false) {
			$return = gSession::get('footer_extra');
			$return .= '<img src="'.U('core-cron/').'" />';
		}
		if($_GET['ajax']) return;
		
		static $synlogin_checked = false;
		if(!$synlogin_checked && self::getInstance()->uid > 0 && mt_rand(0,100) < 20) {
			if(!gSession::get('synlogin')) {
				gSession::set('synlogin', gUser::synlogin(self::getInstance()->uid));
			}
			$return .= gSession::get('synlogin');
			gSession::set('footer_extra', $return);
		}
		$synlogin_checked = true;

		if($code==='') {//get the extra code
			gSession::set('footer_extra', null);
			return $return;
		} else {
			$return .= $code;
			gSession::set('footer_extra', $return);
		}
	}
	
	static function gthrow($msg, $fwd='', $type = 'galaxyException', $e = null) {
    if(IS_CLI) exit($msg);
    throw new $type($msg, $fwd, $e);
	}
}
?>